package com.javacoo.xservice.base.utils;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.ObjectUtils;

import com.alibaba.fastjson.JSONObject;
import com.javacoo.xservice.base.Constants;
import com.javacoo.xservice.base.security.util.SecurityUtil;

/**
 * 常见的辅助类
 * <p>
 * 说明:
 * </p>
 * <li></li>
 * 
 * @author DuanYong
 * @since 2017年3月17日下午2:15:10
 */
public final class DataUtil {
	private static final byte[] KEY = {9, -1, 0, 5, 39, 8, 6, 19};
	private DataUtil() {
	}

	/**
	 * 十进制字节数组转十六进制字符串
	 * 
	 * @param b
	 * @return
	 */
	public static final String byte2hex(byte[] b) { // 一个字节数，转成16进制字符串
		StringBuilder hs = new StringBuilder(b.length * 2);
		String stmp = "";
		for (int n = 0; n < b.length; n++) {
			// 整数转成十六进制表示
			stmp = Integer.toHexString(b[n] & 0XFF);
			if (stmp.length() == 1){
				hs.append("0").append(stmp);	
			}else{
				hs.append(stmp);
			}
		}
		return hs.toString(); 
	}

	/**
	 * 十六进制字符串转十进制字节数组
	 * 
	 * @param hs
	 * @return
	 */
	public static final byte[] hex2byte(String hs) {
		byte[] b = hs.getBytes();
		int two = 2;
		if ((b.length % two) != 0){
			throw new IllegalArgumentException("长度不是偶数");
		}
		byte[] b2 = new byte[b.length / 2];
		for (int n = 0; n < b.length; n += two) {
			String item = new String(b, n, 2);
			// 两位一组，表示一个字节,把这样表示的16进制字符串，还原成一个十进制字节
			b2[n / 2] = (byte) Integer.parseInt(item, 16);
		}
		return b2;
	}

	/**
	 * 这个方法可以通过与某个类的class文件的相对路径来获取文件或目录的绝对路径。 通常在程序中很难定位某个相对路径，特别是在B/S应用中。
	 * 通过这个方法，我们可以根据我们程序自身的类文件的位置来定位某个相对路径。
	 * 比如：某个txt文件相对于程序的Test类文件的路径是../../resource/test.txt，
	 * 那么使用本方法Path.getFullPathRelateClass("../../resource/test.txt",Test.class)
	 * 得到的结果是txt文件的在系统中的绝对路径。
	 * 
	 * @param relatedPath
	 *            相对路径
	 * @param cls
	 *            用来定位的类
	 * @return 相对路径所对应的绝对路径
	 * @throws IOException
	 *             因为本方法将查询文件系统，所以可能抛出IO异常
	 */
	public static final String getFullPathRelateClass(String relatedPath, Class<?> cls) {
		String path = null;
		if (relatedPath == null) {
			throw new NullPointerException();
		}
		String clsPath = getPathFromClass(cls);
		File clsFile = new File(clsPath);
		String tempPath = clsFile.getParent() + File.separator + relatedPath;
		File file = new File(tempPath);
		try {
			path = file.getCanonicalPath();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return path;
	}

	/**
	 * 获取class文件所在绝对路径
	 * 
	 * @param cls
	 * @return
	 * @throws IOException
	 */
	public static final String getPathFromClass(Class<?> cls) {
		String path = null;
		if (cls == null) {
			throw new NullPointerException();
		}
		URL url = getClassLocationURL(cls);
		if (url != null) {
			path = url.getPath();
			if (Constants.JAR.equalsIgnoreCase(url.getProtocol())) {
				try {
					path = new URL(path).getPath();
				} catch (MalformedURLException e) {
				}
				int location = path.indexOf("!/");
				if (location != -1) {
					path = path.substring(0, location);
				}
			}
			File file = new File(path);
			try {
				path = file.getCanonicalPath();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return path;
	}

	/**
	 * 判断对象是否Empty(null或元素为0)<br>
	 * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
	 * 注意：此处不处理Collection为空的情况
	 * @param pObj
	 *            待检查对象
	 * @return boolean 返回的布尔值
	 */
	public static final boolean isEmpty(Object pObj) {
		if (pObj == null){
			return true;
		}
		if (pObj == ""){
			return true;
		}
		if (pObj instanceof String) {
			if (((String) pObj).trim().length() == 0) {
				return true;
			}
//		} else if (pObj instanceof Collection<?>) {
//			if (((Collection<?>) pObj).size() == 0) {
//				return true;
//			}
		} else if (pObj instanceof Map<?, ?>) {
			if (((Map<?, ?>) pObj).size() == 0) {
				return true;
			}
		}
		return false;
	}

	/**
	 * 判断对象是否为NotEmpty(!null或元素>0)<br>
	 * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
	 * 
	 * @param pObj
	 *            待检查对象
	 * @return boolean 返回的布尔值
	 */
	public static final boolean isNotEmpty(Object pObj) {
		if (pObj == null){
			return false;
		}
		if (pObj == ""){
			return false;
		}
		if (pObj instanceof String) {
			if (((String) pObj).trim().length() == 0) {
				return false;
			}
		} else if (pObj instanceof Collection<?>) {
			if (((Collection<?>) pObj).size() == 0) {
				return false;
			}
		} else if (pObj instanceof Map<?, ?>) {
			if (((Map<?, ?>) pObj).size() == 0) {
				return false;
			}
		}
		return true;
	}

	/**
	 * JS输出含有\n的特殊处理
	 * 
	 * @param pStr
	 * @return
	 */
	public static final String replace4JsOutput(String pStr) {
		pStr = pStr.replace("\r\n", "<br/>&nbsp;&nbsp;");
		pStr = pStr.replace("\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
		pStr = pStr.replace(" ", "&nbsp;");
		return pStr;
	}

	/**
	 * 分别去空格
	 * 
	 * @param paramArray
	 * @return
	 */
	public static final String[] trim(String[] paramArray) {
		if (ArrayUtils.isEmpty(paramArray)) {
			return paramArray;
		}
		String[] resultArray = new String[paramArray.length];
		for (int i = 0; i < paramArray.length; i++) {
			String param = paramArray[i];
			resultArray[i] = StringUtils.trim(param);
		}
		return resultArray;
	}

	/**
	 * 获取类的class文件位置的URL
	 * 
	 * @param cls
	 * @return
	 */
	private static URL getClassLocationURL(final Class<?> cls) {
		if (cls == null){
			throw new IllegalArgumentException("null input: cls");
		}
		URL result = null;
		final String clsAsResource = cls.getName().replace('.', '/').concat(".class");
		final ProtectionDomain pd = cls.getProtectionDomain();
		if (pd != null) {
			final CodeSource cs = pd.getCodeSource();
			if (cs != null){
				result = cs.getLocation();
			}
			if (result != null) {
				if (Constants.FILE.equals(result.getProtocol())) {
					try {
						if (result.toExternalForm().endsWith(Constants.DOT_JAR) || result.toExternalForm().endsWith(Constants.DOT_ZIP)){
							result = new URL("jar:".concat(result.toExternalForm()).concat("!/").concat(clsAsResource));
						}else if (new File(result.getFile()).isDirectory()){
							result = new URL(result, clsAsResource);
						}
					} catch (MalformedURLException ignore) {
					}
				}
			}
		}
		if (result == null) {
			final ClassLoader clsLoader = cls.getClassLoader();
			result = clsLoader != null ? clsLoader.getResource(clsAsResource)
					: ClassLoader.getSystemResource(clsAsResource);
		}
		return result;
	}

	/** 初始化设置默认值 */
	public static final <K> K ifNull(K k, K defaultValue) {
		if (k == null) {
			return defaultValue;
		}
		return k;
	}

	/**
	 * 在json字符串中查找指定key对应的值
	 * <p>
	 * 说明:
	 * </p>
	 * <li></li>
	 * 
	 * @author DuanYong
	 * @param jsonStr
	 *            json字符串
	 * @param key
	 *            指定key
	 * @return key对应的值/空
	 * @since 2017年7月5日上午10:48:30
	 */
	public static String findValueByKey(String jsonStr, String key) {
		try {
			String keyRegex = "\"" + key + "\":\"(.*?)\"";
			Pattern pattern = Pattern.compile(keyRegex, Pattern.CASE_INSENSITIVE);
			Matcher matcher = pattern.matcher(jsonStr);
			while (matcher.find()) {
				return matcher.group(1);
			}
		} catch (Exception e) {
		}
		return "";
	}
    
	/**
	 * 对象转换为MAP
	 * <p>说明:</p>
	 * <li></li>
	 * @author DuanYong
	 * @param obj
	 * @return
	 * @since 2017年7月12日下午4:22:18
	 */
	@SuppressWarnings("unchecked")
	public static Map<String, Object> toMap(Object obj) {
		if(obj instanceof JSONObject){
			return FastJsonUtil.stringToCollect(obj.toString());
		}
		return InstanceUtil.transBean2Map(obj);
	}
	/**
	 * 对象转String
	 * <p>说明:</p>
	 * <li></li>
	 * @author DuanYong
	 * @param obj
	 * @return
	 * @since 2017年9月8日上午10:40:24
	 */
	public static String toString(Object obj) {
		if(obj instanceof Optional){
			Optional<?> optional = (Optional<?>)obj;
			return optional.map(o->getString(o)).orElse("");
		}
		return getString(obj);
	}
	
	private static String getString(Object obj){
		if(obj instanceof String){
			return obj.toString();
		}
		return FastJsonUtil.toJSONString(obj);
	}
	/**
	 * 加密数据
	 * <p>说明:</p>
	 * <li></li>
	 * @author DuanYong
	 * @param msg
	 * @return
	 * @since 2018年3月22日下午12:34:15
	 */
	public static String encryptDes(String msg){
		return SecurityUtil.encryptDes(msg, KEY);
	}
	/**
	 * 解密数据
	 * <p>说明:</p>
	 * <li></li>
	 * @author DuanYong
	 * @param msg
	 * @return
	 * @since 2018年3月22日下午12:34:25
	 */
	public static String decryptDes(String msg){
		return SecurityUtil.decryptDes(msg, KEY);
	}
	/**
	 * 判断对象所有字段是否都为空
	 * <p>说明:</p>
	 * <li></li>
	 * @author DuanYong
	 * @param o
	 * @return
	 * @since 2018年4月10日下午1:31:34
	 */
	public static boolean allFieldIsNull(Object o){
	    try{
	        for(Field field:o.getClass().getDeclaredFields()){
	            field.setAccessible(true);//把私有属性公有化
	            Object object = field.get(o);
	            if(!ObjectUtils.isEmpty(object)){
	            	return false;
	            }
	        }
	    }catch (Exception e){
	        e.printStackTrace();
	    }
	    return true;
	}
	 public static void main(String[] args) {
	        String encrypt = encryptDes("sogoodtea");
	        System.out.println(encrypt);
	        System.out.println(decryptDes(encrypt));
	    }
	
}